package grouper;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import database.*;
import database.table.DBTableData;
import datagram.Datagram;
import datagram.Matchgram;
import datagram.Scalegram;

public class CompoundGrouper extends Grouper {
	private double tolerance;
	
	public CompoundGrouper( DBTableData data, double tolerance ) {
		super(data);
		this.tolerance = tolerance;
	}
	
	public void group() {
		//ArrayList<Datagram> datagramList = new ArrayList<Datagram>();
		ArrayList<Group> groupList = new ArrayList<Group>();
		
		BufferedImage image;
		Datagram element;
		int gid, gcol;
		double diff, mindiff;
		
		// Create group column, or select it if existant
		gcol = data.addColumn("Group", Integer.class);
		if (gcol == -1)
			gcol = data.getColumnIndex("Group");
		
		// Define group for each element
		for (int row = 0; row < data.getRowCount(); row++) {
			gid = -1;
			
			try {
				// Read pivot element
				image = ImageIO.read(data.getBlobStreamAt(row, "image"));
				element = new Matchgram( image, 200, Matchgram.METHOD);
				
				// Find closest existant datagram
				mindiff = -1;
				for (int d = 0; d < groupList.size(); d++) {
					diff = groupList.get(d).datagram.difference(element);
					if (mindiff < 0 || diff < mindiff) {
						gid = d;
						mindiff = diff;
					}
				}
				
				// If no group found or closest datagram is too different, create new group
				if (gid == -1 || mindiff > tolerance) {
					groupList.add(new Group(element));
					gid = groupList.size() - 1;
				}
			} catch (IOException e) {
				//System.out.println("ERROR: could not read image for id = " + data.data.get(row).get(0));
				System.out.println(e.getMessage());
			}
			
			groupList.get(gid).add(row);
			//data.setValueAt(gid, row, gcol);
		}
		
		for (int g = 0; g < groupList.size(); g++) {
			for (int p = 0; p < groupList.size(); p++) {
				if (p != g && groupList.get(p).difference(groupList.get(g)) < tolerance) {
					System.out.println("Merging " + p + " to " + g);
					groupList.get(g).merge(groupList.get(p));
					groupList.remove(p--);
				}
			}
			
			for (int row: groupList.get(g).list)
				data.setValueAt(g, row, gcol);
		}
		
		data.sort( gcol );
	}
	
	private class Group {
		Datagram datagram;
		ArrayList<Integer> list;
		
		public Group( Datagram datagram ) {
			this.datagram = datagram;
			this.list = new ArrayList<Integer>();
		}
		
		public void add(int id) {
			list.add(id);
		}
		
		public void merge( Group g ) {
			list.addAll(g.list);
		}
		
		public double difference( Group g ) {
			return datagram.difference(g.datagram);
		}
	}

}
